#include "FunTrace.h"
#include <http.h>
#include "HTTPUtils.h"
#include <eikenv.h>
#include <eikappui.h>
#include <eikapp.h>
#include <euserhl.h>

#include <aknglobalnote.h> 

static void PrintNoteL(TRefByValue<const TDesC> aFormat, ...)
    {
    VA_LIST list;
    VA_START(list, aFormat);
    TBuf<256> buf;
    buf.FormatList(aFormat, list);
    VA_END(list);
	CAknGlobalNote* globalNote = CAknGlobalNote::NewLC();
	globalNote->ShowNoteL(EAknGlobalInformationNote, buf); 
    CleanupStack::PopAndDestroy(globalNote);
    }


static void SetCookie(RHTTPSession& aSession, RHTTPRequest aRequest, const TDesC8& aCookieName, const TDesC8& aCookieValue)
	{
	TFunTrace funTrace(__PRETTY_FUNCTION__);
	RStringPool string_pool = aSession.StringPool();
	RHTTPHeaders headers = aRequest.GetHeaderCollection();
	RStringF cookie_rsf = string_pool.StringF(HTTP::ECookie,RHTTPSession::GetTable());
	THTTPHdrVal field_value;
	field_value.SetStrF (cookie_rsf);
	headers.SetFieldL(cookie_rsf, field_value);
	
	THTTPHdrVal cookie_hdr;
	RStringF cookie_name_rsf = string_pool.StringF(HTTP::ECookieName,RHTTPSession::GetTable());
	RString name = string_pool.OpenStringL (aCookieName);
	cookie_hdr.SetStr (name);
	headers.SetParamL (cookie_rsf, cookie_name_rsf, cookie_hdr, 0);
	name.Close();
	
	RStringF cookie_value_rsf = string_pool.StringF(HTTP::ECookieValue,RHTTPSession::GetTable());
	RString value = string_pool.OpenStringL(aCookieValue);
	cookie_hdr.SetStr (value);
	headers.SetParamL (cookie_rsf, cookie_value_rsf, cookie_hdr, 0); 
	value.Close();
	}

void RHTTPRequestSetCookie(RHTTPSession& aSession, RHTTPRequest aRequest, const TDesC8& aCookieName, const TDesC8& aCookieValue)
	{
	TFunTrace funTrace(__PRETTY_FUNCTION__);
	RStringPool string_pool = aSession.StringPool();
	RHTTPHeaders headers = aRequest.GetHeaderCollection();
	RStringF cookie_rsf = string_pool.StringF(HTTP::ECookie,RHTTPSession::GetTable());
	THTTPHdrVal field_value;
	field_value.SetStrF (cookie_rsf);
	headers.SetFieldL(cookie_rsf, field_value);
	
	THTTPHdrVal cookie_hdr;
	RStringF cookie_name_rsf = string_pool.StringF(HTTP::ECookieName,RHTTPSession::GetTable());
	RString name = string_pool.OpenStringL (aCookieName);
	cookie_hdr.SetStr (name);
	headers.SetParamL (cookie_rsf, cookie_name_rsf, cookie_hdr, 0);
	name.Close();
	
	RStringF cookie_value_rsf = string_pool.StringF(HTTP::ECookieValue,RHTTPSession::GetTable());
	RString value = string_pool.OpenStringL(aCookieValue);
	cookie_hdr.SetStr (value);
	headers.SetParamL (cookie_rsf, cookie_value_rsf, cookie_hdr, 0); 
	value.Close();
	}

HBufC8* RHTTPRequestGetCookie(RHTTPSession& aSession, RHTTPResponse aResponse, const TDesC8& aCookieName)
{
	TFunTrace funTrace(__PRETTY_FUNCTION__);
	RStringF strCookieField = aSession.StringPool().StringF(HTTP::ESetCookie, RHTTPSession::GetTable ( ) );
	THTTPHdrVal valCookieName, valCookieValue;
	RStringF strCookieName = aSession.StringPool().StringF(HTTP::ECookieName, RHTTPSession::GetTable ( ) );
	RStringF strCookieValue = aSession.StringPool().StringF(HTTP::ECookieValue, RHTTPSession::GetTable ( ) );
	if( aResponse.GetHeaderCollection().GetParam(strCookieField, strCookieName, valCookieName) == KErrNone &&
		valCookieName.Str().DesC() == aCookieName &&
		aResponse.GetHeaderCollection().GetParam(strCookieField, strCookieValue, valCookieValue) == KErrNone
		)
		{
		return valCookieValue.Str().DesC().AllocL();
		}
	return NULL;
}

// *****************

CHTTPTransactionTarget* CHTTPTransactionTarget::NewLC()
{
TFunTrace funTrace(__PRETTY_FUNCTION__);
CHTTPTransactionTarget* ret = new (ELeave) CHTTPTransactionTarget;
	CleanupStack::PushL(ret);
	ret->ConstructL();
	return ret;
}

CHTTPTransactionTarget* CHTTPTransactionTarget::NewL()
{
TFunTrace funTrace(__PRETTY_FUNCTION__);
CHTTPTransactionTarget* ret = NewLC();
	CleanupStack::Pop(ret);
	return ret;
}

void CHTTPTransactionTarget::ConstructL()
	{
	TFunTrace funTrace(__PRETTY_FUNCTION__);
	iBody.CreateL(1024);	
	}


CHTTPTransactionTarget::CHTTPTransactionTarget() : iRun(NULL), iRunError(NULL), iRunBodyData(NULL)
	{
	
	}

void CHTTPTransactionTarget::SetRun(scalp::CFunction<void(RHTTPTransaction, THTTPEvent, TInt, TPtrC8)>* aRun)
{
	TFunTrace funTrace(__PRETTY_FUNCTION__);
	delete iRun;
	iRun = aRun;
}

void CHTTPTransactionTarget::SetRunBodyData(scalp::CFunction<void(RHTTPTransaction, THTTPEvent, TInt, TPtrC8, TInt)>* aRunBodyData)
	{
	TFunTrace funTrace(__PRETTY_FUNCTION__);
	delete iRunBodyData;
	iRunBodyData = aRunBodyData;
	}


void CHTTPTransactionTarget::SetRunError(scalp::CFunction<TInt(TInt, RHTTPTransaction, THTTPEvent)>* aRunError)
	{
	TFunTrace funTrace(__PRETTY_FUNCTION__);
	delete iRunError;
	iRunError = aRunError;	
	}

void CHTTPTransactionTarget::MHFRunL(RHTTPTransaction aTransaction, const THTTPEvent& aEvent)
{
TFunTrace funTrace(__PRETTY_FUNCTION__);
	
if(aEvent.iStatus < KErrNone) iLastError = aEvent.iStatus;
	  switch (aEvent.iStatus)
		{
		case THTTPEvent::EUnrecoverableError:
			iLastError = KErrNotReady; // for Symbian 5th ed + 
		  break;
			  
		case THTTPEvent::EGotResponseHeaders:
			{
			iBody.Zero();
			iLastError = KErrNone;
			}
		  break;

		case THTTPEvent::EGotResponseBodyData:
			{
		      MHTTPDataSupplier* body = aTransaction.Response().Body();
		      TPtrC8 part;
		      body->GetNextDataPart(part);
		      TInt partLength = part.Length();
		      if(part.Length() + iBody.Length() > iBody.MaxLength() )
		    	  iBody.ReAllocL(part.Length() + iBody.Length());	    	  	    	  
	    	  iBody.Append(part);	    	  	    	  
		      body->ReleaseData();
		      if(iRunBodyData)
		    	  (*iRunBodyData)(aTransaction, aEvent, iLastError, iBody, partLength);
		    	  
			}
		  break;

		case THTTPEvent::EResponseComplete:
		  break;

		case THTTPEvent::ESucceeded:
		case THTTPEvent::EFailed:
			{
			(*iRun)(aTransaction, aEvent, iLastError, iBody);
			}			
		  break;

		case THTTPEvent::ERedirectedPermanently:
			{
			}
		  break;
			
		case THTTPEvent::ERedirectedTemporarily:
			{
			}
		  break;
			
		default:
			{
			
			}
		  break;
		}
}
TInt CHTTPTransactionTarget::MHFRunError(TInt aError, RHTTPTransaction aTransaction, const THTTPEvent& aEvent)
	{
	TFunTrace funTrace(__PRETTY_FUNCTION__);
	if(iRunError)
		return (*iRunError)(aError, aTransaction, aEvent);
	else
		return aError;
	}
CHTTPTransactionTarget::~CHTTPTransactionTarget()
{
	TFunTrace funTrace(__PRETTY_FUNCTION__);
	delete iRun;
	delete iRunError;
	delete iRunBodyData;
	iBody.Close();
}

// *****************

void CHTTPTransactionSource::SetPostDataL(const TDesC8& aPostData)
	{
	TFunTrace funTrace(__PRETTY_FUNCTION__);
	delete iPostData;
	iPostData = aPostData.AllocL();
	}
TBool CHTTPTransactionSource::GetNextDataPart(TPtrC8& aDataPart)
	{
	TFunTrace funTrace(__PRETTY_FUNCTION__);
		aDataPart.Set( *iPostData );
		return ETrue;	
	}
void CHTTPTransactionSource::ReleaseData()
	{
	TFunTrace funTrace(__PRETTY_FUNCTION__);
	}
TInt CHTTPTransactionSource::OverallDataSize()
	{
	TFunTrace funTrace(__PRETTY_FUNCTION__);
		return iPostData->Length();
		//return KErrNotFound; // chunked transfer causes issues over my wi-fi, no idea why
	}
TInt CHTTPTransactionSource::Reset()
	{
TFunTrace funTrace(__PRETTY_FUNCTION__);
		return KErrNotSupported;
	}

CHTTPTransactionSource::~CHTTPTransactionSource()
	{
	TFunTrace funTrace(__PRETTY_FUNCTION__);
	delete iPostData;
	}


void RHTTPRequestSetHeaderL(RHTTPSession& aSession, RHTTPRequest aRequest, TInt aHdrField, const TDesC8& aHdrValue)
  {
	TFunTrace funTrace(__PRETTY_FUNCTION__);
	RHTTPHeaders hdr = aRequest.GetHeaderCollection();
	RStringF valStr = aSession.StringPool().OpenFStringL(aHdrValue);
	CleanupClosePushL(valStr);
	THTTPHdrVal val(valStr);
	hdr.SetFieldL(aSession.StringPool().StringF(aHdrField,
		RHTTPSession::GetTable()), val);
	CleanupStack::PopAndDestroy();  // valStr
  }

void RHTTPSessionSetHeaderL(RHTTPSession& aSession, TInt aHdrField, const TDesC8& aHdrValue)
  {
	RHTTPHeaders httpHeader = aSession.RequestSessionHeadersL();
	RStringF valStr = aSession.StringPool().OpenFStringL(aHdrValue);
	CleanupClosePushL(valStr);
	THTTPHdrVal val(valStr);
	httpHeader.SetFieldL(aSession.StringPool().StringF(aHdrField,
		RHTTPSession::GetTable()), val);
	CleanupStack::PopAndDestroy();  // valStr
  }


RHTTPTransaction RHTTPSessionOpenTransactionL(RHTTPSession& aSession, const TDesC8& aUrl, MHTTPTransactionCallback& aCallback, TInt aMethod)
	{
	TFunTrace funTrace(__PRETTY_FUNCTION__);
	TUriParser8 uri;
	uri.Parse( aUrl );
	RStringF method = aSession.StringPool().StringF(aMethod,RHTTPSession::GetTable());
	CleanupClosePushL(method);
	RHTTPTransaction transaction = aSession.OpenTransactionL(uri, aCallback, method);	
	CleanupStack::PopAndDestroy(&method);
	return transaction;
	}

const TDesC8& CDeflateDecompressor::DecompressGZipL(const TDesC8& aGzipBuffer)
	{
	// skip the Gzip header
	TInt startCompressedBlocks = 10;
	{
	TInt flag = aGzipBuffer[3];
	if(flag & (1 << 2)) // FEXTRA
		{
		TInt xlen = aGzipBuffer[startCompressedBlocks+1] << 8 + aGzipBuffer[startCompressedBlocks];
		startCompressedBlocks += xlen;
		}
	if(flag & (1 << 3)) // FNAME
		for( ; aGzipBuffer[startCompressedBlocks] ; ++startCompressedBlocks);
	if(flag & (1 << 4)) // FCOMMENT
		for( ; aGzipBuffer[startCompressedBlocks] ; ++startCompressedBlocks);
	if(flag & (1 << 1)) // FHCRC
		startCompressedBlocks += 2;
	}
	// Inflate
	iInput.Set(aGzipBuffer.Mid(startCompressedBlocks, aGzipBuffer.Length() - startCompressedBlocks));
	iDecompressor->ResetL(*this);
	while (iDecompressor->InflateL())
		;
	return iOutputBuf;
	}

const TDesC8& CDeflateDecompressor::DecompressGZip2L(const TDesC8& aGzipBuffer)
	{
	LCleanedupHandle<RFs> fs;
	{
	#ifdef __WINSCW__
	TFileName path = _L("C:");
	#else
	TFileName path = CEikonEnv::Static()->EikAppUi()->Application()->AppFullName().Left(2);
	#endif
	TFileName privatePath;
	User::LeaveIfError(fs->Connect());
	fs->PrivatePath(privatePath);
	path.Append(privatePath);
	fs->MkDirAll(path);	
	User::LeaveIfError(fs->SetSessionPath(path));
	}
	
	{
	LCleanedupHandle<RFile> gzFile;
	User::LeaveIfError(gzFile->Replace(*fs, _L("SmrtConnect.gz"), EFileWrite | EFileStream));
	gzFile->Write(aGzipBuffer);
	}
	{
	LCleanedupHandle<RFile> xmlFile;
	User::LeaveIfError(xmlFile->Replace(*fs, _L("SmrtConnect.xml"), EFileWrite | EFileStream));		
	LCleanedupPtr<CEZGZipToFile> gzip ( CEZGZipToFile::NewL(*fs, _L("SmrtConnect.gz"), *xmlFile) );
	while(gzip->InflateL())
		;
	}
	{
	LCleanedupHandle<RFile> xmlFile;
	User::LeaveIfError(xmlFile->Open(*fs, _L("SmrtConnect.xml"), EFileRead | EFileStream));		
	TInt xmlFileSize; xmlFile->Size(xmlFileSize);
	if(xmlFileSize > iOutputBuf.MaxLength())
		iOutputBuf.ReAllocL(xmlFileSize);
	iOutputBuf.Zero();
	User::LeaveIfError(xmlFile->Read(iOutputBuf));
	//fs->Delete(_L("SmrtConnect.gz"));
	//fs->Delete(_L("SmrtConnect.xml"));
	return iOutputBuf;
	}
}

CDeflateDecompressor::CDeflateDecompressor() : iDecompressor(NULL), iOutput(NULL, 0)
	{
	
	}

CDeflateDecompressor* CDeflateDecompressor::NewLC()
	{
	CDeflateDecompressor* ret = new (ELeave) CDeflateDecompressor;
	CleanupStack::PushL(ret);
	ret->ConstructL();
	return ret;
	}
CDeflateDecompressor* CDeflateDecompressor::NewL()
	{
	CDeflateDecompressor* ret = CDeflateDecompressor::NewLC();
	CleanupStack::Pop();
	return ret;
	}

void CDeflateDecompressor::ConstructL()
	{
	iOutputBuf.CreateMaxL(32);
	iOutputBuf.SetLength(1); // such that iOutputBuf[0] in InitializeL does not crash
	iDecompressor = CEZDecompressor::NewL(*this, -CEZDecompressor::EMaxWBits);
	}

void CDeflateDecompressor::InitializeL(CEZZStream &aZStream)
	{
	aZStream.SetInput(iInput);
	iOutput.Set(&iOutputBuf[0] + 0, 0, iOutputBuf.MaxLength() - 0);
	aZStream.SetOutput(iOutput);
	}
void CDeflateDecompressor::NeedInputL(CEZZStream &aZStream)
	{
	aZStream.SetInput(iInput.Mid(aZStream.TotalIn()));
	}
void CDeflateDecompressor::NeedOutputL(CEZZStream &aZStream)
	{
	if(aZStream.TotalOut() == iOutputBuf.MaxLength() )
		iOutputBuf.ReAllocL(iOutputBuf.MaxLength() * 2);
	iOutput.Set(&iOutputBuf[0] + aZStream.TotalOut(), 0, iOutputBuf.MaxLength() - aZStream.TotalOut());
	aZStream.SetOutput(iOutput);
	}
void CDeflateDecompressor::FinalizeL(CEZZStream &aZStream)
	{
	iOutputBuf.SetLength(aZStream.TotalOut());
	}

CDeflateDecompressor::~CDeflateDecompressor()
	{
	iOutputBuf.Close();
	delete iDecompressor;
	}
